using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Experimental.Rendering;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;

public class DoubleBlurRenderPass : ScriptableRenderPass
{
    private static readonly int BlitTextureSize = Shader.PropertyToID("_BlitTextureSize");
    private static readonly int SourceTexture = Shader.PropertyToID("_SourceTexture");
    private static readonly int BlurIntensity = Shader.PropertyToID("_BlurIntensity");
    private static readonly int m_blur = Shader.PropertyToID("_Blur");
    private RTHandle m_Color;
    private RTHandle m_Dest;
    
    RTHandle[] m_BlurMipUp;
    RTHandle _tempColor;

    private UniversalRenderPipelineAsset _asset;
    
    private int[] blurMipUpProperty;
    private int[] blurMipDownProperty;
    
    private  readonly  string  upName = "_BlurMipUp_" ;
    private  readonly  string  downName = "_BlurMipDown_" ;


    private Material m_BlurMaterial;

    private float blur = 5f;
    private float blurIntensity;

    private DoubleBlurVolume _volume;

    private DoubleBlurVolume blurVolume
    {
        get
        {
            if (_volume == null)
            {
                _volume = VolumeManager.instance.stack.GetComponent<DoubleBlurVolume>();
            }

            return _volume;
        }
    }

    public DoubleBlurRenderPass(Material BlurMaterial)
    {
        _volume = VolumeManager.instance.stack.GetComponent<DoubleBlurVolume>();
        m_BlurMaterial = BlurMaterial;
    }
    
    /// <summary>
    /// 考虑通过Render的 RenderTargetBufferSystems进行backBuffer的申请达到复用dest？
    /// </summary>
    /// <param name="m_Color"></param>
    /// <param name="m_Dest"></param>
    public void Setup(RTHandle m_Color)
    {
        
        #if UNITY_EDITOR
        _volume = VolumeManager.instance.stack.GetComponent<DoubleBlurVolume>();
        #endif
        
        this.m_Color = m_Color;
        renderPassEvent = RenderPassEvent.AfterRenderingTransparents;
        blurIntensity = blurVolume.BlurIntensity.value;
        blur = blurVolume.BlurRadius.value*blurIntensity;
        scaleNum =  blurVolume.scaleNum.value;
        _asset = UniversalRenderPipeline.asset;
        switch (_asset.BlurQuality)
        {
            case 0:
                scaleNum = Mathf.Clamp( scaleNum,1,3);
                break;
            case 1:
                scaleNum = Mathf.Clamp( scaleNum,1,5);
                break;
            case 2:
                scaleNum = Mathf.Clamp( scaleNum,1,6);
                break;
        }
        SetUpBlurData(scaleNum);
    }

    private int scaleNum= 3;
    public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
    {
        
        
        if(!blurVolume.ActiveOn.value) return;
        if(blurIntensity==0) return;

        var cmd = renderingData.commandBuffer;
        using (new ProfilingScope(cmd,ProfilingSampler.Get(URPProfileId.DoubleBlur)))
        {
            
            
            var desc = renderingData.cameraData.BlurCanvasDescriptor;
            var uidesc = renderingData.cameraData.UITargetDescriptor;
            m_BlurMaterial.SetFloat(m_blur, blur);
            
            //InitTempColor(uidesc,desc,cmd);
            
            InitRTHandlersOnExecute(desc);

            var source = m_Color;

            
                
            for (int i = 0; i < scaleNum; i++)
            {
                                
                cmd.SetGlobalVector(BlitTextureSize,m_BlurMipUp[i].rt.texelSize);
                //m_BlurMaterial.SetVector("_BlitTextureSize", m_BlurMipUp[i].rt.texelSize);
                Blitter.BlitCameraTexture(cmd,source,m_BlurMipUp[i],RenderBufferLoadAction.DontCare,RenderBufferStoreAction.Store,m_BlurMaterial,0);
                source = m_BlurMipUp[i];
            }
            for (int i = scaleNum - 2; i >= 0; i--)
            {
                                
                cmd.SetGlobalVector(BlitTextureSize ,m_BlurMipUp[i].rt.texelSize);
                //m_BlurMaterial.SetVector("_BlitTextureSize", m_BlurMipUp[i].rt.texelSize);
                Blitter.BlitCameraTexture(cmd,source,m_BlurMipUp[i],RenderBufferLoadAction.DontCare,RenderBufferStoreAction.Store,m_BlurMaterial,1);
                source = m_BlurMipUp[i];
            }
                                
            cmd.SetGlobalVector(BlitTextureSize,m_Color.rt.texelSize);
            // if (blurIntensity < 1)
            // {
            //     cmd.SetGlobalTexture(SourceTexture,_tempColor);
            //     cmd.SetGlobalFloat(BlurIntensity,blurIntensity);
            //     Blitter.BlitCameraTexture(cmd, source, m_Color,RenderBufferLoadAction.DontCare,RenderBufferStoreAction.Store,m_BlurMaterial,2);    
            // }
            // else
            // {
            //     Blitter.BlitCameraTexture(cmd, source, m_Color,RenderBufferLoadAction.DontCare,RenderBufferStoreAction.Store,m_BlurMaterial,1);    
            // }
            
            Blitter.BlitCameraTexture(cmd, source, m_Color,RenderBufferLoadAction.DontCare,RenderBufferStoreAction.Store,m_BlurMaterial,1);    
            
            
            
            
            
            // 
            ConfigureTarget(m_Color);
        }

    }


    private void InitTempColor(RenderTextureDescriptor uiDesc,RenderTextureDescriptor desc,CommandBuffer cmd)
    {

        var tempColorDesc = desc;
        tempColorDesc.depthBufferBits = 0;
        if (blurIntensity < 1)
        {
            switch (_asset.BlurQuality)
            {
                case 0 : 
                    tempColorDesc.width = desc.width>>1;
                    tempColorDesc.height = desc.height>>1;
                    break;
            }
            RenderingUtils.ReAllocateIfNeeded(ref _tempColor, tempColorDesc, FilterMode.Bilinear, TextureWrapMode.Clamp,
                name: "_TempCopyColor");
            Blitter.BlitCameraTexture(cmd,m_Color,_tempColor,RenderBufferLoadAction.DontCare,RenderBufferStoreAction.Store,Blitter.GetBlitMaterial(TextureDimension.Tex2D),0); 
        }
        
    }



    private void InitRTHandlersOnExecute(RenderTextureDescriptor descriptor)
    {
        descriptor.depthBufferBits = 0;
        switch (UniversalRenderPipeline.asset.BlurQuality)
        {
           case 2:
                descriptor.graphicsFormat = SystemInfo.GetGraphicsFormat(DefaultFormat.LDR); 
               break;
           default:
                descriptor.graphicsFormat = GraphicsFormat.B5G6R5_UNormPack16;
                // descriptor.colorFormat = RenderTextureFormat.RGB565;
                descriptor.sRGB = true;
               break;
        }
        for (int i = 0; i < scaleNum; i++)
        {
            switch (_asset.BlurQuality)
            {
                case 2:
                    int halfWidth = descriptor.width >> 1;
                    int halfHeight = descriptor.height >> 1;
                    int newWidth = Mathf.FloorToInt(Mathf.Lerp(descriptor.width ,halfWidth ,blurIntensity));
                    int newHeight = Mathf.FloorToInt(Mathf.Lerp(descriptor.height ,halfHeight ,blurIntensity));
                    descriptor.width = newWidth;
                    descriptor.height = newHeight;
                    break;
                default:
                    descriptor.width >>= 1;
                    descriptor.height >>= 1;
                    break;
            }
            
            RenderingUtils.ReAllocateIfNeeded(ref m_BlurMipUp[i],descriptor,FilterMode.Bilinear,TextureWrapMode.Clamp,name : m_BlurMipUp[i].name);
        }
    }
    
    
    

    private void SetUpBlurData(int scaleNum)
    {
        
        if (blurMipDownProperty == null || blurMipDownProperty.Length != scaleNum)
        {
            blurMipDownProperty = new int[scaleNum];
            for (int i = 0; i < scaleNum; i++)
            {
                blurMipDownProperty[i] = Shader.PropertyToID( downName + i);
            }
        }
        
        if (blurMipUpProperty == null || blurMipUpProperty.Length != scaleNum)
        {
            blurMipUpProperty = new int[scaleNum];
            for (int i = 0; i < scaleNum; i++)
            {
                blurMipUpProperty[i] = Shader.PropertyToID( upName + i);
            }
        }

        if (m_BlurMipUp == null || m_BlurMipUp.Length != this.scaleNum)
        {
            m_BlurMipUp = new RTHandle[scaleNum];
            for (int i = 0; i < scaleNum; i++)
            {
                m_BlurMipUp[i] = RTHandles.Alloc(blurMipUpProperty[i],name:"_BlurMipUp"+i);
            }
        }

        _tempColor = RTHandles.Alloc("_TempCopyColor");

    }



    public void Dispose()
    {
        if (m_BlurMipUp != null)
        {
            foreach (var rt in m_BlurMipUp) { rt?.Release(); } 
        }

        //_tempColor?.Release();
    }
    
    
}
